﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Dungeon_Dive
{
    /// <summary>
    /// This class is responsible for administering the gameplay screen,
    /// and music associated with it.
    /// </summary>
    public class MainScreen : GameScreen
    {
        LogicEngine level; // level handles gameplay

        Song bgmusic;  // background music for Dungeon Dive

        Log log;
        XMLEngine xmlEngine;
        public readonly string SAVEFILENAME = ".\\XML\\autosave.xml";

        /// <summary>
        /// Constructor for MainScreen.
        /// </summary>
        /// <param name="game">Game1 instance MainScreen belongs to</param>
        public MainScreen(Game1 game) : base(game)
        {
            level = new LogicEngine(game);            
            Components.Add(level);
        }

        /// <summary>
        /// Initializes MainScreen.
        /// </summary>
        public override void Initialize()
        {            
            log = (Log)parentGame.Services.GetService(typeof(Log));
            log.Write("MainScreen.Init()");

            xmlEngine = (XMLEngine)parentGame.Services.GetService(typeof(XMLEngine));

            base.Initialize();
        }

        /// <summary>
        /// Loads assets for MainScreen
        /// </summary>
        protected override void LoadContent()
        {
            ContentManager contentManager = (ContentManager)parentGame.Services.GetService(typeof(ContentManager));
            bgmusic = contentManager.Bgmusic;
            MediaPlayer.IsRepeating = true;
            MediaPlayer.Play(bgmusic);                        
            MediaPlayer.Volume = 0.3f;
            MediaPlayer.Pause();
            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            base.Update(gameTime);
        }

        /// <summary>
        /// Activates MainScreen instance, resumes background music.
        /// </summary>
        /// <returns></returns>
        public override bool Show()
        {
            MediaPlayer.Resume();
            return base.Show();
        }

        /// <summary>
        /// Deactivates MainScreen instance and pauses background music.
        /// </summary>
        /// <returns></returns>
        public override bool Hide()
        {
            MediaPlayer.Pause();
            return base.Hide();
        }

        /// <summary>
        /// Resets Dungeon Dive to start a new game session.
        /// </summary>
        public void ResetLevel()
        {
            log.Write("Resetting level");
            MediaPlayer.Stop();
            MediaPlayer.Play(bgmusic);
            MediaPlayer.Pause();
            components.Clear();
            level = new LogicEngine(parentGame);
            level.Initialize();
            components.Add(level);
        }

        /// <summary>
        /// Saves information on current level and current hitpoints to file.
        /// </summary>
        public void SaveProgress()
        {
            string lvl = level.LevelNumber.ToString();
            List<Elements> hits = level.TPC.Tokens;

            xmlEngine.CreateFile(SAVEFILENAME);
            xmlEngine.StartElement("saveinfo");

            xmlEngine.StartElement("level");
            xmlEngine.AddAttribute("number", lvl);            
            xmlEngine.EndElement();

            xmlEngine.StartElement("tokens");
            foreach (Elements e in hits)
            {
                xmlEngine.StartElement("token");
                    xmlEngine.AddAttribute("type", Enum.GetName(typeof(Elements),e));
                xmlEngine.EndElement();
            }

            xmlEngine.EndDocument();
        }

        /// <summary>
        /// Restores status of last game session, specifically, level reached
        /// and hitpoints at the end of last saved gamesession.
        /// </summary>
        /// <returns>true if loading successful</returns>
        public bool LoadProgress()
        {
            log.Write("LoadProgress loadFromXml(" + SAVEFILENAME + ")");
            String lvl = "0";
            String elem = "";       
            List<Elements> tokens = new List<Elements>();

            if (!xmlEngine.OpenFile(SAVEFILENAME))
                return false;

            log.Write("Loaded xml file succesfully.");

            while (elem != "saveinfo") //Read until we find the saveinfo(root) element
            {
                elem = xmlEngine.NextElement();
                log.Write("elem: " + elem);
            }

            elem = xmlEngine.NextElement(); //Get the first element after root

            while (elem != "saveinfo") //Loop until the closing element
            {
                log.Write("elem: " + elem);
                switch (elem)
                {
                    case "level":
                        lvl = xmlEngine.GetAttribute("number");                        
                        break;

                    case "tokens":
                        elem = xmlEngine.NextElement();
                        if (elem == "saveinfo")  //things break down if tokens is empty
                            return false;
                        while (elem != "tokens") //Loop until we find the closing element
                        {
                            log.Write("elem: " + elem);
                            if (elem == "token")
                            {
                                log.Write("attrib: " + xmlEngine.GetAttribute("type"));
                                string type = xmlEngine.GetAttribute("type");
                                switch (type)
                                {
                                    case "Earth":
                                        tokens.Add(Elements.Earth);
                                        break;
                                    case "Water":
                                        tokens.Add(Elements.Water);
                                        break;
                                    case "Air":
                                        tokens.Add(Elements.Air);
                                        break;
                                    case "Fire":
                                        tokens.Add(Elements.Fire);
                                        break;
                                }
                            }
                            elem = xmlEngine.NextElement();
                        }
                        break;

                }
                elem = xmlEngine.NextElement();
            }

            xmlEngine.CloseFile();

            int lvln = Int32.Parse(lvl);
            tokens.Reverse();

            level.LevelNumber = lvln;
            while (!level.TPC.HandleHit(-1)) ;
            foreach (Elements e in tokens)
                level.TPC.AddToken(e);
            level.GenerateLevel();
            
            return true;
        }

    }
}